<?php
declare (strict_types=1);

// +----------------------------------------------------------------------
// | SCApi
// +----------------------------------------------------------------------
// | 版权所有 2021~2022 贾二小 [ http://www.ipsoul.com ]
// +----------------------------------------------------------------------
// | 官方网站: http://www.ipsoul.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( http://doc.ipsoul.com/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库：https://gitee.com/jiaerxiao/scapi
// | github 代码仓库：https://github.com/jiaerxiao/scapi
// +----------------------------------------------------------------------

namespace app\common\service;

use ipip\db\District;
use think\exception\HttpResponseException;
use think\facade\Queue;
use think\facade\Request;
use think\Response;

/**
 * 工具类
 */
class ToolService
{
    /**
     * 返回操作成功的请求
     * @param array $data 返回数据
     * @param string $msg 消息内容
     * @param int $code 返回代码
     * @param string $userName
     * @author 贾二小
     * @since 2021/10/30
     */
    public static function success(array $data = [], string $msg = "操作成功", int $code = 200, string $logName = '')
    {
        $result = ['code' => $code, 'message' => $msg, 'data' => $data];
        if (!empty($logName)) {
            self::log($logName, $msg, $result, 'Y', 1);
        }
        throw new HttpResponseException(Response::create($result, 'json', $code));
    }

    /**
     * 返回操作失败的请求
     * @param string $msg 消息内容
     * @param array $data 返回数据
     * @param int $code 返回代码
     * @author 贾二小
     * @since 2021/10/30
     */
    public static function error(string $msg, array $data = [], int $code = -1, string $logName = '')
    {
        $result = ['code' => $code, 'message' => $msg, 'data' => $data];
        if (!empty($logName)) {
            self::log($logName, $msg, $result, 'N', 2);
        }
        throw new HttpResponseException(Response::create($result, 'json', 200));
    }

    /**
     * 记录日志(队列)
     * @param string $name
     * @param string $message
     * @param array $result
     * @param string $userName
     * @param string $success
     * @param int $type
     * @author 贾二小
     * @since 2021/12/26
     */
    public static function log(string $name, string $message, array $result, string $success = 'Y', int $type = 1): void
    {
        $data = [];
        $data['name'] = $name;
        $data['type'] = $type;
        $data['success'] = $success;
        $data['message'] = $message;
        $data['result'] = json_encode($result, JSON_UNESCAPED_UNICODE);
        $data['ip'] = self::getClientIp(0, true);
        $data['location'] = self::getIPAddress($data['ip']);
        $data['browser'] = self::getClientBrowser();
        $data['os'] = self::getClientOS();
        $data['url'] = Request::url();
        $data['class_name'] = Request::controller();
        $data['method_name'] = Request::action();
        $data['req_method'] = Request::method(true);
        $data['param'] = json_encode(Request::param(), JSON_UNESCAPED_UNICODE);
        $data['date'] = current_date('date');
        $data['time'] = current_date();
        //异步记录日志
        Queue::later(1, 'system/Log', $data);
    }

    /**
     * 根据IP获取省市
     * https://www.ipip.net/product/ip.html
     * @author 贾二小
     * @since 2021/12/26
     */
    public static function getIPAddress($ip): string
    {
        if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return '';
        }
        $district = new District(app()->getRootPath() . 'ipdb/free.ipdb');
        return implode(' ', array_unique($district->find($ip, 'CN')));
    }

    /**
     * 获取客户端操作系统
     * @author 贾二小
     * @since 2021/12/26
     */
    public static function getClientOS(): string
    {
        $agent = $_SERVER['HTTP_USER_AGENT'];
        $os_ver = '';
        //window系统
        if (stripos($agent, 'window')) {
            $os = 'Windows';
            if (preg_match('/nt 6.0/i', $agent)) {
                $os_ver = 'Vista';
            } elseif (preg_match('/nt 10.0/i', $agent)) {
                $os_ver = '10';
            } elseif (preg_match('/nt 6.3/i', $agent)) {
                $os_ver = '8.1';
            } elseif (preg_match('/nt 6.2/i', $agent)) {
                $os_ver = '8.0';
            } elseif (preg_match('/nt 6.1/i', $agent)) {
                $os_ver = '7';
            } elseif (preg_match('/nt 5.1/i', $agent)) {
                $os_ver = 'XP';
            } elseif (preg_match('/nt 5/i', $agent)) {
                $os_ver = '2000';
            } elseif (preg_match('/nt 98/i', $agent)) {
                $os_ver = '98';
            } elseif (preg_match('/nt/i', $agent)) {
                $os_ver = 'nt';
            } else {
                $os_ver = '';
            }
            if (preg_match('/x64/i', $agent)) {
                $os .= '(x64)';
            } elseif (preg_match('/x32/i', $agent)) {
                $os .= '(x32)';
            }
        } elseif (stripos($agent, 'linux')) {
            if (stripos($agent, 'android')) {
                preg_match('/android\s([\d\.]+)/i', $agent, $match);
                $os = 'Android';
                $os_ver = $match[1];
            } else {
                $os = 'Linux';
            }
        } elseif (stripos($agent, 'unix')) {
            $os = 'Unix';
        } elseif (preg_match('/iPhone|iPad|iPod/i', $agent)) {
            preg_match('/OS\s([0-9_\.]+)/i', $agent, $match);
            $os = 'IOS';
            $os_ver = str_replace('_', '.', $match[1]);
        } elseif (stripos($agent, 'mac os')) {
            preg_match('/Mac OS X\s([0-9_\.]+)/i', $agent, $match);
            $os = 'Mac OS X';
            $os_ver = str_replace('_', '.', $match[1]);
        } else {
            $os = 'Other';
        }
        return $os . '_' . $os_ver;
    }

    /**
     * 获取客户端浏览器以及版本号
     * @author 贾二小
     * @since 2021/12/26
     */
    public static function getClientBrowser(): string
    {
        $agent = $_SERVER['HTTP_USER_AGENT'];
        $browser = '';
        $browser_ver = '';
        if (preg_match('/OmniWeb\/(v*)([^\s|;]+)/i', $agent, $regs)) {
            $browser = 'OmniWeb';
            $browser_ver = $regs[2];
        }
        if (preg_match('/Netscape([\d]*)\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'Netscape';
            $browser_ver = $regs[2];
        }
        if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'Safari';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) {
            $browser = 'Internet Explorer';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) {
            $browser = 'Opera';
            $browser_ver = $regs[1];
        }
        if (preg_match('/NetCaptor\s([^\s|;]+)/i', $agent, $regs)) {
            $browser = '(Internet Explorer ' . $browser_ver . ') NetCaptor';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Maxthon/i', $agent, $regs)) {
            $browser = '(Internet Explorer ' . $browser_ver . ') Maxthon';
            $browser_ver = '';
        }
        if (preg_match('/360SE/i', $agent, $regs)) {
            $browser = '(Internet Explorer ' . $browser_ver . ') 360SE';
            $browser_ver = '';
        }
        if (preg_match('/SE 2.x/i', $agent, $regs)) {
            $browser = '(Internet Explorer ' . $browser_ver . ') 搜狗';
            $browser_ver = '';
        }
        if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'FireFox';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Lynx\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'Lynx';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Chrome\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'Chrome';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MicroMessenger\/([^\s]+)/i', $agent, $regs)) {
            $browser = '微信浏览器';
            $browser_ver = $regs[1];
        }
        return $browser . '_' . $browser_ver;
    }

    /**
     * 获取客户端IP地址
     * @param int $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param bool $adv 否进行高级模式获取（有可能被伪装）
     * @return mixed 返回IP
     * @author 贾二小
     * @since 2021/12/26
     */
    public static function getClientIp(int $type = 0, bool $adv = false)
    {
        $type = $type ? 1 : 0;
        static $ip = null;
        if ($ip !== null) {
            return $ip[$type];
        }
        if ($adv) {
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                $pos = array_search('unknown', $arr);
                if (false !== $pos) {
                    unset($arr[$pos]);
                }
                $ip = trim($arr[0]);
            } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            } elseif (isset($_SERVER['REMOTE_ADDR'])) {
                $ip = $_SERVER['REMOTE_ADDR'];
            }
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u", ip2long((string)$ip));
        $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }
}